﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;

namespace FDSimpleModelGenerator.Common
{
    /// <summary>
    /// 默认的缓存实现
    /// </summary>
    public class DefaultCache : ICache
    {
        private static ConcurrentDictionary<string, CacheItem> _cacheData = new ConcurrentDictionary<string, CacheItem>();
        private static object _sync = new object();

        public T Get<T>(string key)
        {
            var result = GetValue<T>(key, out bool success);
            if (!success)
            {
                return default(T);
            }
            return result;
        }

        public T Get<T>(string key, Func<T> addIfNotExists, TimeSpan expires)
        {
            var result = default(T);
            Action addNotExists = () =>
            {
                result = addIfNotExists();
                if (result != null)
                {
                    Set(key, result, expires);
                }
            };
            if (!_cacheData.ContainsKey(key))
            {
                addNotExists();
                return result;
            }
            result = GetValue<T>(key, out bool success);
            if (!success)
            {
                addNotExists();
            }
            return result;
        }

        public bool Set<T>(string key, T value, TimeSpan expires)
        {
            return SetValue(key, value, expires);
        }

        private T GetValue<T>(string key, out bool success)
        {
            success = false;
            if (_cacheData.TryGetValue(key, out CacheItem item))
            {
                return item == null ? default : item.GetData<T>(out success);
            }

            return default;
        }

        private bool SetValue<T>(string key, T data, TimeSpan expires)
        {
            _cacheData.AddOrUpdate(key, new CacheItem(data, expires), (oKey, oldValue) => new CacheItem(data, expires));
            return true;
        }

        private T ConvertToT<T>(object obj)
        {
            if (obj == null)
            {
                return default(T);
            }

            return (T)Convert.ChangeType(obj, typeof(T));
        }

        class CacheItem
        {
            private object Data
            {
                get
                {
                    if (Expires > DateTime.Now)
                    {
                        return _data;
                    }

                    return null;
                }
            }

            private DateTime Expires { get; set; }

            private object _data;

            public CacheItem(object data, TimeSpan expires)
            {
                _data = data;
                Expires = DateTime.Now + expires;
            }

            public CacheItem()
            {
            }

            public T GetData<T>(out bool success)
            {
                success = true;
                if (DateTime.Now >= Expires || _data == null)
                {
                    success = false;
                    return default;
                }

                return (T)_data;//Convert.ChangeType(_data, typeof(T));
            }

            public bool IsEmpty => Expires == DateTime.MinValue;
        }
    }
}
